package com.heima.search.service.impl;

import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.model.user.pojos.ApUser;
import com.heima.search.service.ApUserSearchService;
import com.heima.search.service.ArticleSearchService;
import com.heima.utils.thread.ApThreadLocalUtil;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;

/**
 * @author ybw
 * @version 1.0
 * @date 2021/12/21 13:46
 */
@Service
public class ArticleSearchServiceImpl implements ArticleSearchService {
  @Autowired private RestHighLevelClient restHighLevelClient;
  @Autowired private ApUserSearchService apUserSearchService;
  /**
   * 文章关键字搜索
   *
   * @param userSearchDto
   * @return
   */
  @Override
  public ResponseResult search(UserSearchDto userSearchDto) {
    if (ObjectUtils.isEmpty(userSearchDto)) {
      return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
    }
    try {
      // 获取用户id
      ApUser apUser = ApThreadLocalUtil.getUser();
      // 保存搜索记录
      apUserSearchService.insert(userSearchDto.getSearchWords(), apUser.getId());

      // 设置索引
      SearchRequest searchRequest = new SearchRequest("app_info_article");
      // 设置条件
      SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
      // 设置文本搜索
      BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
      QueryStringQueryBuilder stringQueryBuilder =
          QueryBuilders.queryStringQuery(userSearchDto.getSearchWords())
              .field("title")
              .field("content")
              .defaultOperator(Operator.OR);
      boolQueryBuilder.must(stringQueryBuilder);

      // 设置时间范围
      RangeQueryBuilder rangeQueryBuilder =
          QueryBuilders.rangeQuery("publishTime").lt(userSearchDto.getMinBehotTime().getTime());
      boolQueryBuilder.filter(rangeQueryBuilder);

      // 设置排序
      sourceBuilder.sort("publishTime", SortOrder.DESC);

      // 设置分页
      sourceBuilder.size(userSearchDto.getPageSize());
      sourceBuilder.from(userSearchDto.getPageNum());

      // 设置高亮
      HighlightBuilder highlightBuilder = new HighlightBuilder();
      highlightBuilder.field("title").preTags("<font style='color:red'>").postTags("</font>");
      sourceBuilder.highlighter(highlightBuilder);

      // 查询
      sourceBuilder.query(boolQueryBuilder);
      searchRequest.source(sourceBuilder);
      SearchResponse searchResponse =
          restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

      if (ObjectUtils.isEmpty(searchResponse)) {
        return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
      }
      // 获取命中数据
      SearchHits searchHits = searchResponse.getHits();
      SearchHit[] hits = searchHits.getHits();
      if (ObjectUtils.isEmpty(hits)) {
        return ResponseResult.okResult(200, "未查询到数据");
      }

      // 封装返回值对象
      ArrayList<Map> list = new ArrayList<>();
      for (SearchHit hit : hits) {
        Map<String, Object> map = hit.getSourceAsMap();
        // 获取高亮域
        Map<String, HighlightField> highlightFields = hit.getHighlightFields();
        if (!ObjectUtils.isEmpty(highlightFields)) {
          Text[] highLight = highlightFields.get("title").getFragments();
          // 转换为字符串
          String title = StringUtils.join(highLight);
          // 高亮标题
          map.put("h_title", title);
        } else {
          map.put("h_title", map.get("title"));
        }
        list.add(map);
      }
      return ResponseResult.okResult(list);
    } catch (IOException e) {
      e.printStackTrace();
      return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
    }
  }
}
